package server;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.concurrent.Callable;

import protocol.Info;
import registration.CheckUserData;
import registration.PersonalData;
import certificate.X509CertificateHandler;

public class RegistrationWorker implements Callable
{
    private Socket socket;
    private PersonalData data;

    public RegistrationWorker( Socket socket )
    {
        this.socket = socket;
    }

    private Certificate generateCertificate()
    {
        Certificate cert = null;
        try
        {
            String dnString = "CN=" + data.getfName() + " " + data.getlName() + ", OU=" + data.getpesel();
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance( "RSA" );
            SecureRandom random = SecureRandom.getInstance( "SHA1PRNG" );
            keyGen.initialize( 2048, random );
            KeyPair pair = keyGen.generateKeyPair();
            cert = X509CertificateHandler.generate( Server.DNName, pair, "SHA1withRSA", 30, dnString );
        }
        catch( NoSuchAlgorithmException e )
        {
            e.printStackTrace();
        }
        catch( CertificateException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch( IOException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch( GeneralSecurityException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return cert;
    }

    @Override
    public Object call()
    {
        InputStream in;
        ObjectInputStream oin = null;
        Object received;
        OutputStream out;
        ObjectOutputStream oout = null;
        Certificate cert = null;
        try
        {
            in = socket.getInputStream();
            oin = new ObjectInputStream( in );
            out = socket.getOutputStream();
            oout = new ObjectOutputStream( out );
            received = oin.readObject();
            if( received instanceof PersonalData )
            {
                System.out.println( "Got PersonalData" );
                /*
                 * 3. przyjmujemy dane i sprawdzamy poprawnosc
                 */
                data = (PersonalData)received;
                System.out.println( "Sprawdzam poprawnosc danych..." );
                try
                {
                    boolean result = CheckUserData.check( data );
                    if( result == false )
                        return null;
                }
                catch( org.postgresql.util.PSQLException e )
                {
                    e.printStackTrace();
                    oout.writeObject( Info.MSG_REG_FAIL + " There is a problem with PKW servers, please try again some other time." );
                }
                System.out.println( "Zgadza się, czekam na certyfikat klienta." );
                received = oin.readObject();
                if( received instanceof Certificate )
                {
                    System.out.println( "Dostalem certyfikat od klienta, zwroce go do serwera zeby sobie zapisal." );
                    cert = (Certificate)received;
                    oout.writeObject( Info.MSG_ALL_GOOD );
                }
            }
            else
            {
                System.out.println( "Not instanceof PersonalData" );
                oout.writeObject( Info.MSG_REG_FAIL );
            }
        }
        catch( IOException e )
        {
            e.printStackTrace();
        }
        catch( ClassNotFoundException e )
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if( oin != null )
                    oin.close();
                if( oout != null )
                    oout.close();
                if( socket != null )
                    socket.close();
            }
            catch( IOException e )
            {
                e.printStackTrace();
            }
        }
        return cert;
    }
}
